/*****************************************************************************/
/*!	\file		PIS10Handlers.c
*	\brief 		C Source code file for the PIS10 Stack Example
	\par        Dalian Yunxing Tech Co., Ltd.

				Dalian, China
				Phone   : +86 (411) 8825 4852
				Email   : yx@yunxing.tech
*/
/*****************************************************************************/
#include "IEC61850Functions.h"
#include "IEC61850Types.h"
#include "PIS10CreateServerClient.h"

#include <stdio.h>
#include <string.h>
#include "UserInput.h"


void printServerList(struct ConnectionsList *ConnectionsList);
unsigned int GetServerIndexFromUser();
void GetFileNameFromUser(char * messageString, char * userInput);

/******************************************************************************
*       SelectCSWI Function Definition
******************************************************************************/
/*!  \brief        This function performs an IEC61850 Select on the CSWI with the value passed in
 *
 *   \ingroup       Callback Handlers
 *
 *   \param[in]     inCtrlValue      	A Boolean that holds the value that the control will be Selected with
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes SelectCSWI(Boolean inCtrlValue)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic CtrlDAID = {0}; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData CtrlDAData = {0}; // Always initialize the structure to 0 to avoid Garbage data value
	struct IEC61850_ControlParameters CtrlControlParams = {0};

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	/* Setup the Data Attribute ID (DAID) Struct - We set this to the CtlVal of the Control*/
	CtrlDAID.Generic_type = IEC61850_DAID_GENERIC;
	CtrlDAID.uiField1 = 1;
	CtrlDAID.uiField2 = 1;
	CtrlDAID.uiField3 = 0;
	CtrlDAID.uiField4 = 0;
	CtrlDAID.uiField5 = 0;

	/* Setup the Data Attribute Data Struct */
	CtrlDAData.uiBitLength = sizeof(Boolean) * 8; //Set the size of the data in bits
	CtrlDAData.ucType = IEC61850_DATATYPE_BOOLEAN; //set the type of the data
	CtrlDAData.pvData = &inCtrlValue; //Set a pointer to the data

	/* Perform the Select, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_ControlSelect(myIEC61850Object, (struct IEC61850_DataAttributeID*)&CtrlDAID, &CtrlDAData, CtrlControlParams);


	/* If the Select failed alert the user */
	if(eErrorCode != IEC61850_ERROR_NONE)
	{
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "CSWI Select failed:(%i) %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}
	else
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}

/******************************************************************************
*       OperateCSWI Function Definition
******************************************************************************/
/*!  \brief        This function performs an IEC61850 Operate on the CSWI with the value passed in
 *
 *   \ingroup       Callback Handlers
 *
 *   \param[in]     inCtrlValue      	A Boolean that holds the value that the control will be operated to
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes OperateCSWI(Boolean inCtrlValue)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic CtrlDAID = {0}; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData CtrlDAData = {0}; // Always initialize the structure to 0 to avoid Garbage data value
	struct IEC61850_ControlParameters CtrlControlParams = {0};

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	/* Setup the Data Attribute ID (DAID) Struct - We set this to the CtlVal of the Control*/
	CtrlDAID.Generic_type = IEC61850_DAID_GENERIC;
	CtrlDAID.uiField1 = 1;
	CtrlDAID.uiField2 = 1;
	CtrlDAID.uiField3 = 0;
	CtrlDAID.uiField4 = 0;
	CtrlDAID.uiField5 = 0;

	/* Setup the Data Attribute Data Struct */
	CtrlDAData.uiBitLength = sizeof(Boolean) * 8; //Set the size of the data in bits
	CtrlDAData.ucType = IEC61850_DATATYPE_BOOLEAN; //set the type of the data
	CtrlDAData.pvData = &inCtrlValue; //Set a pointer to the data

	/* Perform the Operate, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_ControlOperate(myIEC61850Object, (struct IEC61850_DataAttributeID*)&CtrlDAID, &CtrlDAData, CtrlControlParams);

	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Operate Succeeded Update the local value for the gui*/
		SetCSWICtlVal(inCtrlValue);
	}
	else
	{
		/* If the Operate failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "CSWI Operate failed:(%i) %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}



/******************************************************************************
*       OperateGGIO Function Definition
******************************************************************************/
/*!  \brief        This function performs an IEC61850 Operate on the GGIO with the value passed in
 *
 *   \ingroup       Callback Handlers
 *
 *   \param[in]     inCtrlValue      	A Boolean that holds the value that the control will be operated to
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes OperateGGIO(Boolean inCtrlValue)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic CtrlDAID = {0}; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData CtrlDAData = {0}; // Always initialize the structure to 0 to avoid Garbage data value
	struct IEC61850_ControlParameters CtrlControlParams = {0};

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	/* Setup the Data Attribute ID (DAID) Struct - We set this to the CtlVal of the Control*/
	CtrlDAID.Generic_type = IEC61850_DAID_GENERIC;
	CtrlDAID.uiField1 = 2;
	CtrlDAID.uiField2 = 1;
	CtrlDAID.uiField3 = 0;
	CtrlDAID.uiField4 = 0;
	CtrlDAID.uiField5 = 0;

	/* Setup the Data Attribute Data Struct */
	CtrlDAData.uiBitLength = sizeof(Boolean) * 8; //Set the size of the data in bits
	CtrlDAData.ucType = IEC61850_DATATYPE_BOOLEAN; //set the type of the data
	CtrlDAData.pvData = &inCtrlValue; //Set a pointer to the data

	/* Perform the Operate, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_ControlOperate(myIEC61850Object, (struct IEC61850_DataAttributeID*)&CtrlDAID, &CtrlDAData, CtrlControlParams);

	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Operate Succeeded Update the local value for the gui*/
		SetGGIOCtlVal(inCtrlValue);
	}
	else
	{
		/* If the Operate failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "GGIO Operate failed:(%i) %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}




/******************************************************************************
*       UpdateMMXUPhsAMagi Function Definition
******************************************************************************/
/*!  \brief        This function performs an IEC61850 Update on the UpdateMMXUPhsAMagi with the value passed in
 *
 *   \ingroup       Callback Handlers
 *
 *   \param[in]     inUpdateValue      	An Integer32 that holds the value that the UpdateMMXUPhsAMagi will be updated to
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes UpdateMMXUPhsAMagi(Integer32 inUpdateValue)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic updateDAID = {0}; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData updateDAData = {0}; // Always initialize the structure to 0 to avoid Garbage data value

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	/* Setup the Data Attribute ID (DAID) Struct */
	updateDAID.Generic_type = IEC61850_DAID_GENERIC;
	updateDAID.uiField1 = 3;
	updateDAID.uiField2 = 0;
	updateDAID.uiField3 = 0;
	updateDAID.uiField4 = 0;
	updateDAID.uiField5 = 0;

	/* Setup the Data Attribute Data Struct */
	updateDAData.uiBitLength = sizeof(Integer32) * 8; //Set the size of the data in bits
	updateDAData.ucType = IEC61850_DATATYPE_INT32; //set the type of the data
	updateDAData.pvData = &inUpdateValue; //Set a pointer to the data

	/* Perform the Update, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_Update(myIEC61850Object, (struct IEC61850_DataAttributeID*)&updateDAID, &updateDAData, 1); //count of 1 as only 1 element is being updated

	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetMMXUPhsAMagi(inUpdateValue);
	}
	else
	{
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "UpdateMMXUPhsAMagi Update failed:(%i) %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}




/******************************************************************************
*       UpdateMMXUPhsBMagi Function Definition
******************************************************************************/
/*!  \brief        This function performs an IEC61850 Update on the UpdateMMXUPhsBMagi with the value passed in
 *
 *   \ingroup       Callback Handlers
 *
 *   \param[in]     inUpdateValue      	An Integer32 that holds the value that the UpdateMMXUPhsBMagi will be updated to
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes UpdateMMXUPhsBMagi(Integer32 inUpdateValue)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic updateDAID = { 0 }; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData updateDAData = { 0 }; // Always initialize the structure to 0 to avoid Garbage data value

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	/* Setup the Data Attribute ID (DAID) Struct */
	updateDAID.Generic_type = IEC61850_DAID_GENERIC;
	updateDAID.uiField1 = 4;
	updateDAID.uiField2 = 0;
	updateDAID.uiField3 = 0;
	updateDAID.uiField4 = 0;
	updateDAID.uiField5 = 0;

	/* Setup the Data Attribute Data Struct */
	updateDAData.uiBitLength = sizeof(Integer32) * 8; //Set the size of the data in bits
	updateDAData.ucType = IEC61850_DATATYPE_INT32; //set the type of the data
	updateDAData.pvData = &inUpdateValue; //Set a pointer to the data

	/* Perform the Update, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_Update(myIEC61850Object, (struct IEC61850_DataAttributeID*)&updateDAID, &updateDAData, 1); //count of 1 as only 1 element is being updated

	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetMMXUPhsBMagi(inUpdateValue);
	}
	else
	{
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "MMXUPhsBMagi Update failed:(%i) %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}




/******************************************************************************
*       UpdateMMXUPhsCMagi Function Definition
******************************************************************************/
/*!  \brief        This function performs an IEC61850 Update on the MMXUPhsCMagi with the value passed in
 *
 *   \ingroup       Callback Handlers
 *
 *   \param[in]     inUpdateValue      	An Integer32 that holds the value that the MMXUPhsCMagi will be updated to
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes UpdateMMXUPhsCMagi(Integer32 inUpdateValue)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic updateDAID = {0}; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData updateDAData = {0}; // Always initialize the structure to 0 to avoid Garbage data value

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	/* Setup the Data Attribute ID (DAID) Struct */
	updateDAID.Generic_type = IEC61850_DAID_GENERIC;
	updateDAID.uiField1 = 5;
	updateDAID.uiField2 = 0;
	updateDAID.uiField3 = 0;
	updateDAID.uiField4 = 0;
	updateDAID.uiField5 = 0;

	/* Setup the Data Attribute Data Struct */
	updateDAData.uiBitLength = sizeof(Integer32) * 8; //Set the size of the data in bits
	updateDAData.ucType = IEC61850_DATATYPE_INT32; //set the type of the data
	updateDAData.pvData = &inUpdateValue; //Set a pointer to the data

	/* Perform the Update, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_Update(myIEC61850Object, (struct IEC61850_DataAttributeID*)&updateDAID, &updateDAData, 1); //count of 1 as only 1 element is being updated

	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetMMXUPhsCMagi(inUpdateValue);
	}
	else
	{
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "MMXUPhsCMagi Update failed:(%i) %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}

enum IEC61850_ErrorCodes UpdateTTNSTnsSv1Magf(Float32 inUpdateValue)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic updateDAID = { 0 }; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData updateDAData = { 0 }; // Always initialize the structure to 0 to avoid Garbage data value

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	/* Setup the Data Attribute ID (DAID) Struct */
	updateDAID.Generic_type = IEC61850_DAID_GENERIC;
	updateDAID.uiField1 = 7;
	updateDAID.uiField2 = 0;
	updateDAID.uiField3 = 0;
	updateDAID.uiField4 = 0;
	updateDAID.uiField5 = 0;

	/* Setup the Data Attribute Data Struct */
	updateDAData.uiBitLength = sizeof(Float32) * 8; //Set the size of the data in bits
	updateDAData.ucType = IEC61850_DATATYPE_FLOAT32; //set the type of the data
	updateDAData.pvData = &inUpdateValue; //Set a pointer to the data

	/* Perform the Update, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_Update(myIEC61850Object, (struct IEC61850_DataAttributeID*)&updateDAID, &updateDAData, 1); //count of 1 as only 1 element is being updated

	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetTTNSTnsSv1Magf(inUpdateValue);
	}
	else
	{
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "UpdateTTNSTnsSv1Magf Update failed:(%i) %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}
enum IEC61850_ErrorCodes UpdateTTNSTnsSv2Magf(Float32 inUpdateValue)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic updateDAID = { 0 }; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData updateDAData = { 0 }; // Always initialize the structure to 0 to avoid Garbage data value

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	/* Setup the Data Attribute ID (DAID) Struct */
	updateDAID.Generic_type = IEC61850_DAID_GENERIC;
	updateDAID.uiField1 = 7;
	updateDAID.uiField2 = 0;
	updateDAID.uiField3 = 0;
	updateDAID.uiField4 = 0;
	updateDAID.uiField5 = 1;

	/* Setup the Data Attribute Data Struct */
	updateDAData.uiBitLength = sizeof(Float32) * 8; //Set the size of the data in bits
	updateDAData.ucType = IEC61850_DATATYPE_FLOAT32; //set the type of the data
	updateDAData.pvData = &inUpdateValue; //Set a pointer to the data

	/* Perform the Update, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_Update(myIEC61850Object, (struct IEC61850_DataAttributeID*)&updateDAID, &updateDAData, 1); //count of 1 as only 1 element is being updated

	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetTTNSTnsSv2Magf(inUpdateValue);
	}
	else
	{
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "UpdateTTNSTnsSv2Magf Update failed:(%i) %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}
enum IEC61850_ErrorCodes UpdateTTNSTnsSv3Magf(Float32 inUpdateValue)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic updateDAID = { 0 }; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData updateDAData = { 0 }; // Always initialize the structure to 0 to avoid Garbage data value

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	/* Setup the Data Attribute ID (DAID) Struct */
	updateDAID.Generic_type = IEC61850_DAID_GENERIC;
	updateDAID.uiField1 = 7;
	updateDAID.uiField2 = 0;
	updateDAID.uiField3 = 0;
	updateDAID.uiField4 = 0;
	updateDAID.uiField5 = 2;

	/* Setup the Data Attribute Data Struct */
	updateDAData.uiBitLength = sizeof(Float32) * 8; //Set the size of the data in bits
	updateDAData.ucType = IEC61850_DATATYPE_FLOAT32; //set the type of the data
	updateDAData.pvData = &inUpdateValue; //Set a pointer to the data

	/* Perform the Update, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_Update(myIEC61850Object, (struct IEC61850_DataAttributeID*)&updateDAID, &updateDAData, 1); //count of 1 as only 1 element is being updated

	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetTTNSTnsSv3Magf(inUpdateValue);
	}
	else
	{
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "UpdateTTNSTnsSv3Magf Update failed:(%i) %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}
/******************************************************************************
*       UpdatePDIFCrvPtsYVal Function Definition
******************************************************************************/
/*!  \brief        This function performs an IEC61850 Update on the PDIFCrvPtsYVal with the value passed in
 *
 *   \ingroup       Callback Handlers
 *
 *   \param[in]     inUpdateValue   A Float32 that holds the value that the element in PDIFCrvPtsYVal will be updated to
 *   \param[in]     inIndex	      	An Integer8 that holds the index of the element in the array to be updates
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes UpdatePDIFCrvPts(CrvPts inUpdateValue, Integer8 inIndex)
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_DataAttributeID_Generic crvPtsArrayDAID; //We use the Generic version as it is easier to assign the Data Attribute IDs
	struct IEC61850_DataAttributeData CrvPtsArrayDAData; // Always initialize the structure to 0 to avoid Garbage data value
	struct IEC61850_DataAttributeData XYValDAData[NUM_CRVPTS_STRUCT_ELEMENTS]; // Always initialize the structure to 0 to avoid Garbage data value

	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

   memset(&crvPtsArrayDAID, 0, sizeof(struct IEC61850_DataAttributeID_Generic));
   memset(&CrvPtsArrayDAData, 0, sizeof(struct IEC61850_DataAttributeData));
   memset(XYValDAData, 0, NUM_CRVPTS_STRUCT_ELEMENTS * sizeof(struct IEC61850_DataAttributeData));

	/* Setup the Data Attribute ID (DAID) Struct */
	crvPtsArrayDAID.Generic_type = IEC61850_DAID_GENERIC;
	crvPtsArrayDAID.uiField1 = 6;
	crvPtsArrayDAID.uiField2 = 0;
	crvPtsArrayDAID.uiField3 = 0;
	crvPtsArrayDAID.uiField4 = 0;
	crvPtsArrayDAID.uiField5 = 0;

	/* Setup the Data Attribute Data Struct */
	CrvPtsArrayDAData.iArrayIndex = inIndex; //Set the index to be updated
	CrvPtsArrayDAData.uiBitLength = NUM_CRVPTS_STRUCT_ELEMENTS; //Set the size of the Array being passed in. 2 elements in this case Xval and YVal
	CrvPtsArrayDAData.ucType = IEC61850_DATATYPE_ARRAY; //set the type of the data
	CrvPtsArrayDAData.pvData = XYValDAData; //Set a pointer to the data

	/* Setup the XVal */
	XYValDAData[0].ucType = IEC61850_DATATYPE_FLOAT32;
	XYValDAData[0].uiBitLength = sizeof(Float32)*8;
	XYValDAData[0].pvData = &(inUpdateValue.xVal);

	/* Setup the YVal */
	XYValDAData[1].ucType = IEC61850_DATATYPE_FLOAT32;
	XYValDAData[1].uiBitLength = sizeof(Float32)*8;
	XYValDAData[1].pvData = &(inUpdateValue.yVal);

	/* Perform the Update, note the IEC61850_DataAttributeID_Generic needs to be typecast to a standard struct IEC61850_DataAttributeID */
	eErrorCode = IEC61850_Update(myIEC61850Object, (struct IEC61850_DataAttributeID*)&crvPtsArrayDAID, &CrvPtsArrayDAData, 1); //count of 1 as only 1 element is being updated

	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetPDIFCrvPts(inIndex, inUpdateValue);
	}
	else
	{
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "PDIFCrvPtsYVal[%d] Update failed:(%i) %s\n", inIndex, eErrorCode, IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return eErrorCode;
}



/******************************************************************************
*       MMSGetConnectionsList Function Definition
******************************************************************************/
/*!  \brief        This function gets the connected server list from IEC61850 and prints it
 *
 *   \ingroup       Callback Handlers
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes MMSGetConnectionsList()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure
	struct ConnectionsList *ConnectionsList = NULL; //create a structure pointer for the Connected Server List

	/* Request the list from the server, passing in a pointer to the above pointer. */
	eErrorCode = IEC61850_GetConnectionsList(myIEC61850Object, &ConnectionsList);
	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		Unsigned32 u32Count = 0;
		/* Set error message to show success */
		snprintf(strError, SIZE_OF_ERROR_STRING, "Get connected server list success.");
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* Print the list */
		printf("\n\tConnected Servers (%u):\n", ConnectionsList->u16NumberOfConnections);
		printf("\tIndex\tDomain Name\t\tIP Address\tConnection Status\n");
		for(u32Count = 0; u32Count < ConnectionsList->u16NumberOfConnections; u32Count++)
		{
			printf("\t%u\t%s\t%s\t%s\n",
			ConnectionsList->ptConnections[u32Count].uiAAIndex,
			ConnectionsList->ptConnections[u32Count].ptDomainName,
			ConnectionsList->ptConnections[u32Count].ptIPAddress,
			ConnectionsList->ptConnections[u32Count].bConnectionState ? "Connected" : "Disconnected"); //status 2 is connected
		}
		/* Wait for user */
		printf("\nPress enter to continue.");
		getchar();
	}
	else
	{
		/* If the function failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "Get connected server list failed: %i: %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode)==NULL?"MMS Error":IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}
	return eErrorCode;
}

/******************************************************************************
*       MMSGetFileAttribs Function Definition
******************************************************************************/
/*!  \brief			This function get the connected server list from IEC61850 and prints it
 *					The function then prompts to selected a server index and files name.
 *					The function the gets the file attributes from the server.
 *
 *   \ingroup       Callback Handlers
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes MMSGetFileAttribs()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	struct tFileAttr ptFileAttributes = {0}; //tFileAttr to hold the returned attributes
	struct tFile sourceFile = { 0 }; //tFile to pass to server to select file or directory
	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure
	struct ConnectionsList *ConnectionsList = NULL; //create a structure pointer for the Connected Server List
	unsigned int fileCount = 0; //file count
	unsigned int uiServerIndex = 0; //selected server index

	eErrorCode = IEC61850_GetConnectionsList(myIEC61850Object, &ConnectionsList); //get the connected server list
	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		printServerList(ConnectionsList); //print the connected server list
		uiServerIndex = GetServerIndexFromUser(); //prompt to select index
		/* prompt for file or directory */
		GetFileNameFromUser("Enter a file name or directory (blank will list the current directory): ", sourceFile.cFileName);

		/* request the attributes */
		eErrorCode = IEC61850_GetFileAttributeValues(myIEC61850Object, uiServerIndex, sourceFile.cFileName, NULL, &ptFileAttributes);

		if(eErrorCode == IEC61850_ERROR_NONE)
		{
			/* Set the Error String to NONE */
			char strError[SIZE_OF_ERROR_STRING] = {0};
			snprintf(strError, SIZE_OF_ERROR_STRING, "Get File attributes success.");
			SetErrorString(strError, SIZE_OF_ERROR_STRING);

			/* Print list of files and attributes */
			printf("\n\n\tReceived attributes for %d file(s):\n", ptFileAttributes.u32NumOfDirectoryEntries);
			printf("\tFile\tTime Stamp\tSize [Bytes]\tFile Name\n");
			for(fileCount = 0; fileCount < ptFileAttributes.u32NumOfDirectoryEntries; fileCount++)
			{
				printf("\t%u:\t%s\t%u\t\t%s\n", fileCount + 1, ptFileAttributes.ptArrayofDirectoryEntries[fileCount].ctLastModified, ptFileAttributes.ptArrayofDirectoryEntries[fileCount].u32FileSize, ptFileAttributes.ptArrayofDirectoryEntries[fileCount].cFileName);
			}

			/* Wait for user */
			printf("\nPress enter to continue.");
			getchar();
		}
		else
		{
			/* If the function failed alert the user */
			char strError[SIZE_OF_ERROR_STRING] = {0};
			snprintf(strError, SIZE_OF_ERROR_STRING, "Get File attributes failed: %i: %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode)==NULL?"MMS Error":IEC61850_ErrorString(eErrorCode));
			SetErrorString(strError, SIZE_OF_ERROR_STRING);
		}
	}
	else
	{
		/* If the function failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "Unable to get connected server list: %i: %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode)==NULL?"MMS Error":IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}
	return eErrorCode;
}

/******************************************************************************
*       GetServerIndexFromUser Function Definition
******************************************************************************/
/*!  \brief         This function Gets an unsigned int index from the user
 *
 *   \ingroup       User Input
 *
 *
 *   \return        The unsigned int value of the input supplied by the user
 ******************************************************************************/
unsigned int GetServerIndexFromUser()
{
	unsigned int returnValue = 0xFFFF;
    char buffer[BUFSIZ];
	printf("Enter index of the connected server: ");
	setbuf(stdin, NULL);
	fgets(buffer, sizeof(buffer), stdin);
	sscanf(buffer, "%u", &returnValue);

	return returnValue;
}

/******************************************************************************
*       GetFileNameFromUser Function Definition
******************************************************************************/
/*!  \brief         This function gets a string from the user
 *
 *   \ingroup       User Input
 *
 *   \param[in]     messageString	A pointer to the char array containing the message to be displayed
 *   \param[in]     userInput		A pointer to the char array to be populated by the file name. Should have 256 elements.
 *
 *   \return        The unsigned int value of the input supplied by the user
 ******************************************************************************/
void GetFileNameFromUser(char * messageString, char * userInput)
{
	int returnError = 0;
    int ch;

	if (messageString == NULL)
	{
        returnError = -1;
	}

	// Get user input
	if (returnError == 0)
    {
        printf("%s", messageString); //print the message
        fflush(stdout);

        if (fgets(userInput, 256, stdin) == NULL) //get user input string
        {
            returnError = -1;
        }
        //sscanf(line, "%255s", userInput); //get string from input
    }

    // If the input string is too long, print out error message
    // It also flush the reset so that it won't affect the next call
    if (returnError == 0)
    {
        if (userInput[strlen(userInput)-1] != '\n')
        {
            // Read the remaining characters
            while (((ch = getchar()) != '\n') && (ch != EOF))
            {
                returnError = -1;
            };

            if (returnError != 0)
            {
                printf("Filename must be shorter than 255 characters. Please try again.\n");
            }
        }
    }

    if (returnError != 0)
    {
        userInput = NULL;
    }
    else
    {
        userInput[strlen(userInput)-1] = '\0';
    }
}

/******************************************************************************
*       PrintServerList Function Definition
******************************************************************************/
/*!  \brief         This function prints the data in a ConnectionsList struct
 *
 *   \ingroup
 *
 *   \param[in]     ConnectionsList   A pointer to the populated ConnectionsList struct
 *
 *   \return        void
 ******************************************************************************/
void printServerList(struct ConnectionsList *ConnectionsList)
{
	unsigned int u32Count = 0;
	printf("\n\tConnected Servers (%u):\n", ConnectionsList->u16NumberOfConnections);
	printf("\tIndex\tDomain Name\t\tIP Address\tConnection Status\n");
	for(u32Count = 0; u32Count < ConnectionsList->u16NumberOfConnections; u32Count++)
	{
		printf("\t%u\t%s\t%s\t%s\n",
			ConnectionsList->ptConnections[u32Count].uiAAIndex,
			ConnectionsList->ptConnections[u32Count].ptDomainName,
			ConnectionsList->ptConnections[u32Count].ptIPAddress,
			ConnectionsList->ptConnections[u32Count].bConnectionState ? "Connected" : "Disconnected"); //status 2 is connected
	}
	printf("\n");
}



/******************************************************************************
*       MMSGetFile Function Definition
******************************************************************************/
/*!  \brief			This function downloads a file from a connected server
 *					The function prompts to selected a server index, remote file name and local file name.
 *
 *   \ingroup       Callback Handlers
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes MMSGetFile()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure
	struct ConnectionsList *ConnectionsList = NULL;
	unsigned int uiServerIndex = 0;
	char remoteFileName[256] = {0};
	char localFileName[256] = {0};
	eErrorCode = IEC61850_GetConnectionsList(myIEC61850Object, &ConnectionsList);
	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		printServerList(ConnectionsList);
		uiServerIndex = GetServerIndexFromUser();
		GetFileNameFromUser("Enter the remote source file name: ", remoteFileName);
		GetFileNameFromUser("Enter the local destination file name: ", localFileName);

		eErrorCode = IEC61850_GetFile(myIEC61850Object, uiServerIndex, remoteFileName, localFileName);
		if(eErrorCode == IEC61850_ERROR_NONE)
		{
			/* Set the Error String to NONE */
			char strError[SIZE_OF_ERROR_STRING] = {0};
			snprintf(strError, SIZE_OF_ERROR_STRING, "Get File success.");
			SetErrorString(strError, SIZE_OF_ERROR_STRING);
		}
	}
	if(eErrorCode != IEC61850_ERROR_NONE)
	{
		/* If the function failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "Get File failed: %i: %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode)==NULL?"MMS Error":IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}
	return eErrorCode;
}

enum IEC61850_ErrorCodes SetFile()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure
	struct ConnectionsList* ConnectionsList = NULL;
	unsigned int uiServerIndex = 0;
	char remoteFileName[256] = { 0 };
	char localFileName[256] = { 0 };
	eErrorCode = IEC61850_GetConnectionsList(myIEC61850Object, &ConnectionsList);
	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		printServerList(ConnectionsList);
		uiServerIndex = GetServerIndexFromUser();
		GetFileNameFromUser("Enter the remote source file name: ", remoteFileName);
		GetFileNameFromUser("Enter the local destination file name: ", localFileName);

		eErrorCode = IEC61850_SetFile(myIEC61850Object, uiServerIndex, remoteFileName, localFileName);
		if (eErrorCode == IEC61850_ERROR_NONE)
		{
			/* Set the Error String to NONE */
			char strError[SIZE_OF_ERROR_STRING] = { 0 };
			snprintf(strError, SIZE_OF_ERROR_STRING, "Set File success.");
			SetErrorString(strError, SIZE_OF_ERROR_STRING);
		}
	}
	if (eErrorCode != IEC61850_ERROR_NONE)
	{
		/* If the function failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "Set File failed: %i: %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode) == NULL ? "MMS Error" : IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}
	return eErrorCode;
}


/******************************************************************************
*       MMSDeleteFile Function Definition
******************************************************************************/
/*!  \brief			This function deletes a file from a connected server.
 *					The function prompts to selected a server index and remote file name for deletion.
 *
 *   \ingroup       Callback Handlers
 *
 *   \return        IEC61850_ERROR_NONE on success
 *   \return        otherwise the relevant enum IEC61850_ErrorCodes on failure
 ******************************************************************************/
enum IEC61850_ErrorCodes MMSDeleteFile()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure
	struct ConnectionsList *ConnectionsList = NULL;
	unsigned int uiServerIndex = 0;
	char remoteFileName[256] = {0};
	Boolean cont = FALSE;
	char userInput[256] = { 0 }; //Buffer to hold the user input

	eErrorCode = IEC61850_GetConnectionsList(myIEC61850Object, &ConnectionsList);
	if(eErrorCode == IEC61850_ERROR_NONE)
	{
		printServerList(ConnectionsList);
		uiServerIndex = GetServerIndexFromUser();
		GetFileNameFromUser("Enter the name of the remote file you wish to delete: ", remoteFileName);

		printf("WARNING: this will permanently delete the file \"%s\" - Do you want to continue? type Y or y: ", remoteFileName);

		if (fgets(userInput, sizeof(userInput), stdin) != NULL)
		{
			switch (userInput[0]) //Base the return val on the input
			{
			case 'y':
			case 'Y':
				cont = TRUE;  
				break;
			default:
				cont = FALSE;  
				break;
			}
		}

		if (cont == TRUE)
		{
			/* send delete file command */
			eErrorCode = IEC61850_DeleteFile(myIEC61850Object, uiServerIndex, remoteFileName);
			if (eErrorCode == IEC61850_ERROR_NONE)
			{
				/* Set the Error String to NONE */
				char strError[SIZE_OF_ERROR_STRING] = { 0 };
				snprintf(strError, SIZE_OF_ERROR_STRING, "Delete File success.");
				SetErrorString(strError, SIZE_OF_ERROR_STRING);
			}
		}
	}

	if(eErrorCode != IEC61850_ERROR_NONE)
	{
		/* If the function failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = {0};
		snprintf(strError, SIZE_OF_ERROR_STRING, "Delete File failed: %i: %s\n", eErrorCode, IEC61850_ErrorString(eErrorCode)==NULL?"MMS Error":IEC61850_ErrorString(eErrorCode));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}
	return eErrorCode;
}

void LogOperate()
{
	char continueMainLoop = 'y';
	Integer32 usrCommand = 0;
	do
	{
		PrintLogMenuView(); /* Initialize the Screen */
		usrCommand = GetCommIndexFromUser(); /* Get the Command from the User */
		switch (usrCommand)
		{
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			QueryLogByTime();
			break;
		case 2:
			QueryLogAfterEnerID();
			break;
		case 3:
			GetLogStatusValues();
			break;
		default:
			break;
		}
	} while (continueMainLoop == 'y');
}
enum IEC61850_ErrorCodes QueryLogByTime()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	struct IEC61850_TimeStamp* pStartTime = NULL;
	struct IEC61850_TimeStamp* pStopTime = NULL;
	struct IEC61850_LogEntries returnedLogEntries = { 0 };
	char* logRef = "ServerIEDExample/LLN0.logName";

	pStartTime = GetIEC61850TimeFromUser();
	pStopTime  = GetIEC61850TimeFromUser();
	eErrorCode = IEC61850_QueryLogByTime(GetMyServerClient(), 0, logRef, pStartTime, pStopTime, &returnedLogEntries);
	printLogVals(&returnedLogEntries);
	if (pStartTime != NULL)
	{
		free(pStartTime);
		pStartTime = NULL;
	}
	if (pStopTime != NULL)
	{
		free(pStopTime);
		pStopTime = NULL;
	}
	IEC61850_FreeLogEntries(&returnedLogEntries);
	return eErrorCode;
}

enum IEC61850_ErrorCodes QueryLogAfterEnerID()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	struct IEC61850_TimeStamp* pStartTime = NULL;
	struct IEC61850_LogEntries returnedLogEntries = { 0 };
	char* logRef = "ServerIEDExample/LLN0.logName";

	Integer32 entryID = 0;

	printf("Please input EnterID:");

#ifdef __PARADIGM__
	scanf("%ld", &entryID); //On BECK an Integer32 is a long int so %ld is needed
#else
	scanf("%d", &entryID);
#endif

	pStartTime = GetIEC61850TimeFromUser();
	eErrorCode = IEC61850_QueryLogAfter(GetMyServerClient(), 0, logRef, pStartTime, entryID, &returnedLogEntries);
	printLogVals(&returnedLogEntries);

	if (pStartTime != NULL)
	{
		free(pStartTime);
		pStartTime = NULL;
	}
	IEC61850_FreeLogEntries(&returnedLogEntries);
	return eErrorCode;
}

enum IEC61850_ErrorCodes GetLogStatusValues()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	struct IEC61850_LogStatus returnedLogStatus = { 0 };

	char* Domain = "ServerIEDExample";
	char* Item = "LLN0$LG$logCBName";
	struct IEC61850_LogStatus tLogStatus = { 0 };

	eErrorCode = IEC61850_GetLogStatusValues(GetMyServerClient(), 0, Domain, Item, &tLogStatus);
	
	printLogStatus(&tLogStatus);
	return eErrorCode;
}
enum IEC61850_ErrorCodes GetDataSetDirectory()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	struct StringList* ptDataSetRefList = StringListMalloc();
	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure
	eErrorCode = IEC61850_GetDataSetDirectory(myIEC61850Object, 0, "CSWI0$BufferedDS", "ServerIEDExample", ptDataSetRefList);
	for (unsigned int uiCount = 0; uiCount < ptDataSetRefList->uiLen; uiCount++)
	{
		printf("\t%u.%s\n", uiCount + 1, ptDataSetRefList->list[uiCount]);
	}
	getchar();
	return eErrorCode;
}
enum IEC61850_ErrorCodes MMSReadOrWrite()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	char continueMainLoop = 'y';
	char usrCommand = 0;
	do
	{
		printf("1) Read\n");
		printf("2) Write\n");
		printf("0) Return to main menu\n");

		usrCommand = GetCommIndexFromUser(); /* Get the Command from the User */

		switch (usrCommand)
		{
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			MMS_Read();
			break;
		case 2:
			MMS_Write();
			break;

		default:
			break;
		}

	} while (continueMainLoop == 'y');
	return eErrorCode;
}
enum IEC61850_ErrorCodes MMS_Read()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	struct StringList* ptDataSetRefList = StringListMalloc();
	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure
	
	Boolean bEnable = TRUE;

	struct tMmsDataItem tDataItem;
	tDataItem.uiSize = 8;
	tDataItem.cType = IEC_MMS_TYPE_BOOLEAN;
	tDataItem.ptData = &bEnable;

	eErrorCode = IEC61850_ReadDirect(myIEC61850Object, 0, "ServerIEDExample", "CSWI0$BR$BufferedCB01$RptEna", &tDataItem,1);

	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		if (bEnable)
		{
			printf("Read value is TRUE\n");
		}
		else
		{
			printf("Read value is FALSE\n");
		}
	}
	else
	{
		printf("Read FAIL\n");
	}
	getchar();
	return eErrorCode;
}
enum IEC61850_ErrorCodes MMS_Write()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	struct StringList* ptDataSetRefList = StringListMalloc();
	IEC61850 myIEC61850Object = GetMyServerClient(); //Get the IEC61850 Structure

	Boolean bEnable = TRUE;

	struct tMmsDataItem tDataItem;
	tDataItem.uiSize = 8;
	tDataItem.cType = IEC_MMS_TYPE_BOOLEAN;
	tDataItem.ptData = &bEnable;

	eErrorCode = IEC61850_WriteDirect(myIEC61850Object, 0, "ServerIEDExample", "CSWI0$BR$BufferedCB01$RptEna", &tDataItem);

	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		printf("Write success\n");
	}
	else
	{
		printf("Write FAIL\n");
	}
	getchar();
	return eErrorCode;
}
void FileOperate()
{
	char continueMainLoop = 'y';
	char usrCommand = 0;
	do
	{
		PrintFileMenuView(); /* Initialize the Screen */

		usrCommand = GetCommIndexFromUser(); /* Get the Command from the User */

		switch (usrCommand)
		{
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			MMSGetFile();
			break;
		case 2:
			SetFile();
			break;
		case 3:
			MMSDeleteFile();
			break;
		case 4:
			MMSGetFileAttribs();
			break;
		default:
			break;
		}

	} while (continueMainLoop == 'y');
}

void SittingGroupOperate()
{
	char continueMainLoop = 'y';
	char usrCommand = 0;
	do
	{
		PrintSettingGroupMenuView(); /* Initialize the Screen */

		usrCommand = GetCommIndexFromUser(); /* Get the Command from the User */

		switch (usrCommand)
		{
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			GetSGValues();
			continueMainLoop = 'n';
			break;
		case 2:
			SelectActiveSG();
			break;
		case 3:
			SelectEditSG();
			break;
		case 4:
			SetEditSG();
			break;
		case 5:
			ConfirmEditSG();
			break;
		case 6:
			GetSGCBValues();
			break;
		default:
			break;
		}

	} while (continueMainLoop == 'y');
}

enum IEC61850_ErrorCodes GetSGValues()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	struct tMmsDataItem tDataMaxNumRcd = { 0 };
	struct tMmsDataItem tDataOpMod = { 0 };
	struct tMmsDataItem tDataMemFull = { 0 };

	char* sDomainName = "ServerIEDExample";
	char sItemNameMaxNumRcd[129] = { 0 };
	char sItemNameOpMod[129] = { 0 };
	char sItemNameMemFull[129] = { 0 };

	Integer32 newValMaxNumRcd = 0, newValOpMod = 0, newValMemFull = 0;

	char userInput[16] = { 0 };
	printf("please select FC:\n1)SG \n2)SE\n:");
	setbuf(stdin, NULL);
	if (fgets(userInput, sizeof(userInput), stdin) != NULL)
	{
		switch (userInput[0])
		{
		case '1':
			strncpy(sItemNameMaxNumRcd, "IARC0$SG$MaxNumRcd$setVal", 129);
			strncpy(sItemNameOpMod, "IARC0$SG$OpMod$setVal", 129);
			strncpy(sItemNameMemFull, "IARC0$SG$MemFull$setVal", 129);
			break;
		case '2':
			strncpy(sItemNameMaxNumRcd, "IARC0$SE$MaxNumRcd$setVal", 129);
			strncpy(sItemNameOpMod, "IARC0$SE$OpMod$setVal", 129);
			strncpy(sItemNameMemFull, "IARC0$SE$MemFull$setVal", 129);
			break;
		}
	}

	tDataMaxNumRcd.uiSize = 32;
	tDataMaxNumRcd.cType = IEC_MMS_TYPE_INTEGER;
	tDataMaxNumRcd.ptData = &newValMaxNumRcd;

	tDataOpMod.uiSize = 32;
	tDataOpMod.cType = IEC_MMS_TYPE_INTEGER;
	tDataOpMod.ptData = &newValOpMod;

	tDataMemFull.uiSize = 32;
	tDataMemFull.cType = IEC_MMS_TYPE_INTEGER;
	tDataMemFull.ptData = &newValMemFull;

	eErrorCode = IEC61850_ReadDirect(GetMyServerClient(), 0, sDomainName, sItemNameMaxNumRcd, &tDataMaxNumRcd, 1);
	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		eErrorCode = IEC61850_ReadDirect(GetMyServerClient(), 0, sDomainName, sItemNameOpMod, &tDataOpMod, 1);
	}
	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		eErrorCode = IEC61850_ReadDirect(GetMyServerClient(), 0, sDomainName, sItemNameMemFull, &tDataMemFull, 1);
	}
	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		SetMaxNumRcd(newValMaxNumRcd);
		SetOpMod(newValOpMod);
		SetMemFull(newValMemFull);
	}
	return eErrorCode;
}

enum IEC61850_ErrorCodes SelectActiveSG()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	char userInput[256] = { 0 };
	char* sDomainName = "ServerIEDExample";
	char* sItemName = "LLN0$SP$SGCB$ActSG";
	struct tMmsDataItem tDataToBeWritten;
	Unsigned8 u8SettingGroupNumber = 0;
	setbuf(stdin, NULL);
	while (u8SettingGroupNumber > 5 || u8SettingGroupNumber < 1)
	{
		memset(userInput, 0, 256);
		printf("please input settinggroup active ID[1-5]:");
		if (fgets(userInput, sizeof(userInput), stdin) != NULL)
		{
			u8SettingGroupNumber = atoi(userInput);
		}
	}
	tDataToBeWritten.cType = IEC_MMS_TYPE_UNSIGNED;
	tDataToBeWritten.uiSize = 8;
	tDataToBeWritten.ptData = &u8SettingGroupNumber;

	eErrorCode = IEC61850_WriteDirect(GetMyServerClient(), 0, sDomainName, sItemName, &tDataToBeWritten);
	return eErrorCode;
}
enum IEC61850_ErrorCodes SelectEditSG()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	char userInput[256] = { 0 };
	char* sDomainName = "ServerIEDExample";
	char* sItemName = "LLN0$SP$SGCB$EditSG";
	struct tMmsDataItem tDataToBeWritten;
	Unsigned8 u8SettingGroupNumber = 0;
	setbuf(stdin, NULL);
	while (u8SettingGroupNumber > 5 || u8SettingGroupNumber < 1)
	{
		memset(userInput, 0, 256);
		printf("please input settinggroup edit ID[1-5]:");
		if (fgets(userInput, sizeof(userInput), stdin) != NULL)
		{
			u8SettingGroupNumber = atoi(userInput);
		}
	}
	tDataToBeWritten.cType = IEC_MMS_TYPE_UNSIGNED;
	tDataToBeWritten.uiSize = 8;
	tDataToBeWritten.ptData = &u8SettingGroupNumber;

	eErrorCode = IEC61850_WriteDirect(GetMyServerClient(), 0, sDomainName, sItemName, &tDataToBeWritten);
	return eErrorCode;
}

enum IEC61850_ErrorCodes SetEditSG()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;

	char* sDomainName        = "ServerIEDExample";
	char* sItemNameMaxNumRcd = "IARC0$SE$MaxNumRcd$setVal";
	char* sItemNameOpMod     = "IARC0$SE$OpMod$setVal";
	char* sItemNameMemFull   = "IARC0$SE$MemFull$setVal";
	char* sItemName = NULL;
	Integer32 newVal = 0;
	struct tMmsDataItem tDataToBeWritten;
	char userInput[16] = { 0 };
	printf("please select reference:\n1)%s \n2)%s\n3)%s\ninput[1-3]:", sItemNameMaxNumRcd, sItemNameOpMod, sItemNameMemFull);
	setbuf(stdin, NULL);
	if (fgets(userInput, sizeof(userInput), stdin) != NULL)
	{
		switch (userInput[0])
		{
		case '1':
			sItemName = sItemNameMaxNumRcd;
			break;
		case '2':
			sItemName = sItemNameOpMod;
			break;
		case '3':
			sItemName = sItemNameMemFull;
			break;
		}
	}

	printf("please input new value:");
	memset(userInput, 0, 16);
	setbuf(stdin, NULL);
	if (fgets(userInput, sizeof(userInput), stdin) != NULL)
	{
		newVal = atoi(userInput);
	}

	tDataToBeWritten.cType = IEC_MMS_TYPE_INTEGER;
	tDataToBeWritten.uiSize = 32;
	tDataToBeWritten.ptData = &newVal;

	eErrorCode = IEC61850_WriteDirect(GetMyServerClient(), 0, sDomainName, sItemName, &tDataToBeWritten);

	return eErrorCode;
}
enum IEC61850_ErrorCodes ConfirmEditSG()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	char* sDomainName = "ServerIEDExample";
	char* sItemName = "LLN0$SP$SGCB$CnfEdit";
	struct tMmsDataItem tDataToBeWritten;
	Boolean cnfEdit = TRUE;

	tDataToBeWritten.cType = IEC_MMS_TYPE_BOOLEAN;
	tDataToBeWritten.uiSize = 8;
	tDataToBeWritten.ptData = &cnfEdit;

	eErrorCode = IEC61850_WriteDirect(GetMyServerClient(), 0, sDomainName, sItemName, &tDataToBeWritten);
	return eErrorCode;
}
enum IEC61850_ErrorCodes GetSGCBValues()
{
	enum IEC61850_ErrorCodes eErrorCode = IEC61850_ERROR_NONE;
	char* sDomainName = "ServerIEDExample";
	char* sItemName = "LLN0$SP$SGCB";

	struct tMmsDataItem tDataSGCB = { 0 };
	struct tMmsDataItem tDataSGCBItems[5] = { 0 };

	struct tMmsDataItem* ptDataNumOfSG = &tDataSGCBItems[0];
	struct tMmsDataItem* ptDataActSG   = &tDataSGCBItems[1];
	struct tMmsDataItem* ptDataEditSG  = &tDataSGCBItems[2];
	struct tMmsDataItem* ptDataCnfEdit = &tDataSGCBItems[3];
	struct tMmsDataItem* ptDataLActTm  = &tDataSGCBItems[4];

	Unsigned8 numOfSG  = 0;
	Unsigned8 actSG    = 0;
	Unsigned8 editSG   = 0;
	Boolean   cnfEdit  = FALSE;
	struct IEC61850_TimeStamp      lastActTm = { 0 };

	tDataSGCB.cType = IEC_MMS_TYPE_STRUCTURE;
	tDataSGCB.uiSize = 5;
	tDataSGCB.ptData = tDataSGCBItems;

	ptDataNumOfSG->cType = IEC_MMS_TYPE_UNSIGNED;
	ptDataNumOfSG->uiSize = 8;
	ptDataNumOfSG->ptData = &numOfSG;

	ptDataActSG->cType = IEC_MMS_TYPE_UNSIGNED;
	ptDataActSG->uiSize = 8;
	ptDataActSG->ptData = &actSG;

	ptDataEditSG->cType = IEC_MMS_TYPE_UNSIGNED;
	ptDataEditSG->uiSize = 8;
	ptDataEditSG->ptData = &editSG;

	ptDataCnfEdit->cType = IEC_MMS_TYPE_BOOLEAN;
	ptDataCnfEdit->uiSize = 8;
	ptDataCnfEdit->ptData = &cnfEdit;

	ptDataLActTm->cType = IEC_MMS_TYPE_UTC_TIME;
	ptDataLActTm->uiSize = 8*8;
	ptDataLActTm->ptData = &lastActTm;


	eErrorCode = IEC61850_ReadDirect(GetMyServerClient(), 0, sDomainName, sItemName, &tDataSGCB, 1);
	if (eErrorCode == IEC61850_ERROR_NONE)
	{
		printf("SGCB Values:\n");
		struct IEC61850_DateTime myDateTime;
		printf("\tSGCB actSG:       [%d]\n", actSG);
		printf("\tSGCB editSG:      [%d]\n", editSG);
		printf("\tSGCB numOfSG:     [%d]\n", numOfSG);
		if (cnfEdit)
		{
			printf("\tSGCB cnfEdit:     [TRUE]\n");
		}
		else
		{
			printf("\tSGCB cnfEdit:     [FALSE]\n");
		}
		memset(&myDateTime, 0, sizeof(struct IEC61850_DateTime));
		//Get Date from IEC61850 Time Stamp
		IEC61850_GetDateFromIEC61850Time(&myDateTime, &lastActTm);
		printf("\tSGCB ActTm:       [%02u/%02u/%u %02u:%02u:%02u]\n", myDateTime.month, myDateTime.tm_mday, myDateTime.year, myDateTime.tm_hour, myDateTime.tm_min, myDateTime.tm_sec);
	}

	return eErrorCode;

}

